package com.eeb.dropwizardmongo.example.resources;

import com.codahale.metrics.annotation.Timed;
import com.eeb.dropwizardmongo.example.api.Assignment;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.mongojack.DBQuery;
import org.mongojack.DBUpdate;
import org.mongojack.JacksonDBCollection;

import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.Map;

@Path("/assignments")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class AssignmentsResource {

    private JacksonDBCollection<Assignment, String> assignments;

    public AssignmentsResource(JacksonDBCollection<Assignment, String> assignments) {
        this.assignments = assignments;
    }

    @GET
    @Produces(value = MediaType.APPLICATION_JSON)
    @Timed
    public Response getAssignments(@QueryParam("track") String track,
                                   @QueryParam("badge") String badge,
                                   @QueryParam("reviewer") String reviewer,
                                   @QueryParam("submissionPoints") Integer submissionPoints,
                                   @QueryParam("reviewPoints") Integer reviewPoints,
                                   @QueryParam("status") String status) throws UnsupportedEncodingException {
        DBQuery.Query query = DBQuery.empty();
        if (track != null)
            query = track.startsWith("-") ?
                    query.notEquals("track", URLEncoder.encode(track.substring(1), "UTF-8")) :
                    query.is("track", URLEncoder.encode(track, "UTF-8"));
        if (badge != null)
            query = badge.startsWith("-") ?
                    query.nor(DBQuery.all("badges", URLEncoder.encode(badge.substring(1), "UTF-8"))) :
                    query.all("badges", URLEncoder.encode(badge, "UTF-8"));
        if (reviewer != null)
            query = reviewer.startsWith("-") ?
                    query.nor(DBQuery.all("reviewers", reviewer.substring(1))) :
                    query.all("reviewers", reviewer);
        if (submissionPoints != null)
            query = submissionPoints < 0 ?
                    query.notEquals("submissionpoints", submissionPoints*-1) :
                    query.is("submissionpoints", submissionPoints);
        if (reviewPoints != null)
            query = reviewPoints < 0 ?
                    query.notEquals("reviewpoints", reviewPoints*-1) :
                    query.is("reviewpoints", reviewPoints);
        if (status != null)
            query = status.startsWith("-") ?
                    query.notEquals("status", status.substring(1)) :
                    query.is("status", status);
        return Response.ok(assignments.find(query).toArray()).build();
    }

    @Path("/{assignment}")
    @GET
    @Produces(value = MediaType.APPLICATION_JSON)
    @Timed
    public Response getAssignment(@PathParam("assignment") String assignment) {
        return Response.ok(assignments.findOne(DBQuery.is("name", assignment))).build();
    }

    @POST
    @Timed
    public Response postAssignment(@Valid Assignment assignment) throws URISyntaxException, UnsupportedEncodingException {
        URI uri = new URI("/" + assignment.getName());
        if (assignments.findOne(DBQuery.is("name", assignment.getName())) == null)
            assignments.insert(assignment);
        return Response.created(uri).entity(assignments.findOne(DBQuery.is("name", assignment.getName()))).build();
    }

    @PUT
    @Timed
    public Response putAssignment(@Valid Assignment Assignment) {
        return Response.status(405).entity("PUT to /assignments/{name} or POST to /assignments").build();
    }

    @Path("/{assignment}")
    @PUT
    @Timed
    public Response putAssignment(@PathParam("assignment") String assignment,
                                  @Valid String json) throws IOException {
        DBQuery.Query query = DBQuery.is("name", assignment);
        Map<String, Object> map = new ObjectMapper().readValue(json, new TypeReference<Map<String, Object>>() {
        });
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue() != null) {
                assignments.update(query, DBUpdate.set(entry.getKey(), entry.getValue()));
            }
        }
        return Response.ok(assignments.findOne(DBQuery.is("name", assignment))).build();
    }

    @Path("/{assignment}")
    @DELETE
    @Timed
    public Response deleteAssignment(@PathParam("assignment") String assignment) {
        assignments.findAndRemove(DBQuery.is("name", assignment));
        return Response.ok(assignments.find().toArray()).build();
    }

}